Introduction
Great! At this point, I’ve run a Matlab script on the children’s raw data to collect XY gaze data for each video/trial they viewed. We start with 68 children.
Right now, I’m putting ALL those kids. Later, I should probably throw out those that were NOT in our AOI analysis. That’s a simple thing to do.
Also, a few of them need to have their xy data corrected because of large offsets.
For now here’s all our data.
# Libraries
library(tidyverse)
Warning message:
In as.POSIXlt.POSIXct(Sys.time()) :
unknown timezone 'zone/tz/2017c.1.0/zoneinfo/America/Los_Angeles'
library(feather)
library(lme4)
library(grid)
library(png)
#library(cowplot)
# Import data (and fix one participant name, and fix Owen as EnglishExposed)
data <- read_feather("../Child Data/childxydata.feather") %>%
mutate(participant = case_when(
participant == "Ab07ov09_22m" ~ "Ab07ov09_32m",
TRUE ~ participant
)) %>%
mutate(language = case_when(
participant == "OwenTwin030212_4y2m" ~ "EnglishExposed",
TRUE ~ language
))
# Get ages
ages <- read_csv("childrenages.csv")
data <- data %>% left_join(ages, by = "participant")
data %>% select(participant,language,age) %>% distinct() # print data table
# Histogram of ages
data %>% select(participant,language,age) %>%
distinct() %>%
ggplot(aes(x = age)) + geom_histogram(fill = "royalblue") + ggtitle("Ages in Full Dataset")

Removing Discarded Kids (to come)
This is the part where I want to remove all children that were not included in the AOI analysis. But I haven’t written the code yet, so.
Shifting Data (to come)
Then there are some kids whose data needs to be corrected because of large offsets which we detected via twopuppies.nb.html. I should list those kids here, too.
Save!
Great. Let’s save this as `cleanedchildxydata.csv’.
# Pull apart condition columns
data <- data %>%
separate(condition, into = c("story", "clipnum", "direction", "media"), sep = "_") %>%
unite(story, clipnum, col = "story", sep = "_") %>%
select(-media)
# A bit more cleaning up
data <- data %>%
mutate(direction = case_when(
direction == "FW" ~ "forward",
direction == "ER" ~ "reversed"
)) %>%
mutate(language = case_when(
language == "SignLanguageExposed" ~ "sign",
language == "EnglishExposed" ~ "english"
)) %>%
mutate(group = as.factor(group),
gender = as.factor(gender),
language = as.factor(language),
story = as.factor(story),
direction = as.factor(direction))
# Save as csv and feather (feather preserves column types for R)
write_csv(data,"../Child Data/cleanedchildxydata.csv")
write_feather(data,"../Child Data/cleanedchildxydata.feather")
Participant Table
Now we can present the following table about our participants.
participants <- data %>%
select(participant, gender, language, age) %>%
distinct()
participants_n <- participants %>%
count(gender, language) %>%
spread(gender, n)
participants_age <- participants %>%
group_by(language) %>%
summarise(age_m = round(mean(age), 1),
age_sd = round(sd(age), 1),
age_min = range(age)[1],
age_max = range(age)[2]) %>%
mutate(age_range = paste(age_min, age_max, sep = " - ")) %>%
select(-age_min, -age_max) %>%
mutate(age_mean = paste(age_m, age_sd, sep = "±")) %>%
select(-age_m, -age_sd) %>%
select(language, age_mean, age_range)
left_join(participants_n, participants_age, by = "language")
Analysis Time!
First, let’s trim each participant’s data, getting rid of the first 60 samples (0.5 secs). Then we’ll get the the mean x and y coordinate for each story for each participant.
# Just to load data again
data <- read_feather("../Child Data/cleanedchildxydata.feather")
data <- data %>%
group_by(participant,trial) %>%
slice(60:n())
means <- data %>%
group_by(participant,trial) %>%
summarise(x = mean(x,na.rm=TRUE),
y = mean(y,na.rm=TRUE))
head(means,10)
And I can get x or y plots of one participant across 4 stories. Let’s do Emmet. We’ll set the x and y limits to the whole width of the Tobii monitor (1600x1200). But because Tobii considers (0,0) to be the upper left corner (and not the bottom left corner), we also need to flip the y axis.
emmet <- filter(data,participant=="emmet_12_10_12_CODA") %>% mutate(y = y*-1)
ggplot(emmet,aes(x=x,y=y,color=story)) + geom_point(size=0.1) + geom_path() + facet_wrap("story",ncol=4,nrow=2) + guides(color="none") + scale_x_continuous(limit=c(0,1600)) + scale_y_continuous(limit=c(-1200,0))

Cool, yeah?
IQR
Now let’s get the middle 50% (aka the IQR) of x and y for each participant’s story (we’ve already trimmed the first 60 samples). That should also take care of further weird outliers. And we are defining “viewing space” as the IQR of the x and y axis.
iqr <- data %>%
group_by(participant,trial) %>%
summarise(xIQR = IQR(x,na.rm=TRUE),
yIQR = IQR(y,na.rm=TRUE),
xmed = median(x, na.rm=TRUE),
ymed = median(y, na.rm=TRUE)) %>%
ungroup()
head(iqr,10)
# Join participant info back into IQR table
participantinfo <- data %>%
select(participant, trial, age, group, gender, language, story, direction, mark, repetition) %>%
distinct()
iqr <- left_join(iqr, participantinfo, by = c("participant","trial"))
And check out the histograms. I truncated the y-axis at 100 to better see outliers.
iqr %>%
gather(axis,iqr,xIQR:yIQR) %>%
ggplot(aes(x=iqr,fill=axis)) + geom_histogram() + facet_grid(axis~.) +
coord_cartesian(ylim = c(0,50))

So we see some outliers. Who are those? Let’s get a table of them. Review those AFTER I’ve done the cleanups of course.
xoutliers <- iqr %>%
arrange(desc(xIQR)) %>%
slice(1:10)
youtliers <- iqr %>%
arrange(desc(yIQR)) %>%
slice(1:10)
Next, check the medians.
iqr %>%
gather(axis,med,xmed:ymed) %>%
ggplot(aes(x=med,fill=axis)) + geom_histogram() + facet_grid(axis~.) +
coord_cartesian(ylim = c(0,50))

SO I need to review those too. After cleaning up/removing kids.
iqr.gather <- iqr %>% gather(axis,value,xIQR:ymed)
iqr.iqr <- filter(iqr.gather,axis=="xIQR" | axis=="yIQR")
iqr.med <- filter(iqr.gather,axis=="xmed" | axis=="ymed")
ggplot(iqr.iqr,aes(x=language,y=value,fill=direction)) +
geom_boxplot() + theme(axis.text.x=element_text(angle=45,hjust=1)) +
facet_grid(.~axis)

And the median x and y position (this assumes all calibrations are correct):
ggplot(iqr.med,aes(x=language,y=value,fill=direction)) +
geom_boxplot() + theme(axis.text.x=element_text(angle=45,hjust=1)) +
facet_grid(.~axis)

First, does reversal and language experience have an effect on X IQR? We have random intercepts for each participant and media, and a random slope adjustment for reversed for each participant.
xiqr.reversal <- lmer(xIQR ~ direction * language + (direction|participant) + (1|story), data = iqr)
summary(xiqr.reversal)$coefficients
Estimate Std. Error t value
(Intercept) 40.651974 2.419302 16.8031816
directionreversed 19.761856 12.158529 1.6253492
languagesign -9.019172 3.794033 -2.3771991
directionreversed:languagesign -17.019853 19.293332 -0.8821625
That’s fine, we’re not exactly predicting changes along the x-axis. The y-axis is what we are really interested in! :)
yiqr.reversal <- lmer(yIQR ~ direction * language + (direction|participant) + (1|story), data = iqr)
summary(yiqr.reversal)$coefficients
Estimate Std. Error t value
(Intercept) 61.89272 4.258159 14.535089
directionreversed 25.17458 8.578833 2.934500
languagesign -17.24320 6.789348 -2.539743
directionreversed:languagesign -21.29204 13.607362 -1.564744
Viewing Space Charts
I want to learn how to make rectangle plots so here we go. Using each participant’s four x and y medians and 4 x and y IQRs (one set for each story, for 4 stories). So I can get the logic and code down. Let’s assume all calibrations were correct. Here’s the chart for the whole media size of 1440x1080 (as reported in Tobii).
# In this order, we'll get a grand median by taking a participant's median across their 4 stories, than the median for forward and reverse across all participants.
medians <- iqr %>%
group_by(participant,direction) %>%
summarise(xIQR = median(xIQR,na.rm=TRUE),
yIQR = median(yIQR,na.rm=TRUE),
xmed = median(xmed,na.rm=TRUE),
ymed = median(ymed,na.rm=TRUE)) %>%
group_by(direction) %>%
summarise(xIQR = median(xIQR,na.rm=TRUE),
yIQR = median(yIQR,na.rm=TRUE),
x = median(xmed,na.rm=TRUE),
y = median(ymed,na.rm=TRUE))
medians <- medians %>%
mutate(y = y*-1,
xmin = x-(xIQR/2),
xmax = x+(xIQR/2),
ymin = y-(yIQR/2),
ymax = y+(yIQR/2))
img <- readPNG("cindy.png")
g <- rasterGrob(img, interpolate=TRUE, width=unit(1,"npc"), height=unit(1,"npc"))
ggplot(medians, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_minimal() + xlim(0,1440) + ylim(-1080,0)

# ggplot(iqr.global, aes(fill=direction,color=direction)) +
# annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
# geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
# theme_minimal() + xlim(0,1440) + ylim(-1080,0) +
# geom_hline(yintercept=-1080+885) +
# geom_hline(yintercept=-1080+525) +
# annotate(geom="text", x = 300, y = -1080+555, label = "upper shoulder point") +
# annotate(geom="point", x = 535, y = -1080+525) +
# annotate(geom="text", x = 535, y = -1080+910, label = "height line") +
# annotate(geom="rect", xmin = 535, xmax = 535+365, ymin = -525-551, ymax = -1080+525, fill="maroon", color="black", alpha=0.5) +
# annotate(geom="text", x = 700, y = -900, label = "torso")
Viewing Space Charts for Individuals
Now let’s see the variation in viewing spaces for all our individuals. Should be fun.
iqr.individuals <- iqr %>%
rename(x = xmed,
y = ymed) %>%
mutate(y = y*-1,
xmin = x-(xIQR/2),
xmax = x+(xIQR/2),
ymin = y-(yIQR/2),
ymax = y+(yIQR/2))
ggplot(iqr.individuals, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_minimal() + xlim(0,1440) + ylim(-1080,0) + facet_wrap("direction") +
ggtitle("with IQRs")

Now let’s make Outer Limits charts which is IQR +/- 2 SDs. But I want to change that because I don’t like the idea of mixing IQRs and SDs.
sd.individuals <- select(sd.individuals,participant,media,xsd,ysd)
Error in select(sd.individuals, participant, media, xsd, ysd) :
object 'sd.individuals' not found
LS0tCnRpdGxlOiAiUmF3IFhZIERhdGEgKHN0dWR5MmNoaWxkcmVuKSIKYXV0aG9yOiAiQWRhbSBTdG9uZSwgUGhEIiAKZGF0ZTogJ2ByIGZvcm1hdChTeXMuRGF0ZSgpLCAiJW0tJWQtJVkiKWAnCm91dHB1dDoKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IHNwYWNlbGFiCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyBUaGlzIGlzIHRvIGdldCBhbGwga2lkcycgX3Byb2Nlc3NlZF8gWFkgZGF0YSBpbnRvIG9uZSBzaW5nbGUgZmlsZS4gU2hvdWxkIG9ubHkgcnVuIHdoZW4gbmVlZGVkLiAKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZmVhdGhlcikKbGlicmFyeShsbWU0KQpsaWJyYXJ5KHBuZykKbGlicmFyeShncmlkKQoKY3N2cGF0aCA9ICIuLi9DaGlsZCBEYXRhL194eWRhdGEvIgpmaWxlcyA8LSBkaXIocGF0aCA9IGNzdnBhdGgsIHBhdHRlcm4gPSAiX3h5ZGF0YSIpCmZpbGVzIDwtIHBhc3RlKGNzdnBhdGgsIGZpbGVzLCBzZXA9IiIpCmRhdGEgPC0gZmlsZXMgJT4lCiAgbWFwKHJlYWRfY3N2KSAlPiUKICByZWR1Y2UocmJpbmQpCndyaXRlX2ZlYXRoZXIoZGF0YSwgIi4uL0NoaWxkIERhdGEvY2hpbGR4eWRhdGEuZmVhdGhlciIpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCkdyZWF0ISBBdCB0aGlzIHBvaW50LCBJJ3ZlIHJ1biBhIE1hdGxhYiBzY3JpcHQgb24gdGhlIGNoaWxkcmVuJ3MgcmF3IGRhdGEgdG8gY29sbGVjdCBYWSBnYXplIGRhdGEgZm9yIGVhY2ggdmlkZW8vdHJpYWwgdGhleSB2aWV3ZWQuIFdlIHN0YXJ0IHdpdGggNjggY2hpbGRyZW4uIAoKUmlnaHQgbm93LCBJJ20gcHV0dGluZyBBTEwgdGhvc2Uga2lkcy4gKipMYXRlciwgSSBzaG91bGQgcHJvYmFibHkgdGhyb3cgb3V0IHRob3NlIHRoYXQgd2VyZSBOT1QgaW4gb3VyIEFPSSBhbmFseXNpcy4gVGhhdCdzIGEgc2ltcGxlIHRoaW5nIHRvIGRvLioqIAoKQWxzbywgYSBmZXcgb2YgdGhlbSBuZWVkIHRvIGhhdmUgdGhlaXIgeHkgZGF0YSBjb3JyZWN0ZWQgYmVjYXVzZSBvZiBsYXJnZSBvZmZzZXRzLiAKCkZvciBub3cgaGVyZSdzICoqYWxsKiogb3VyIGRhdGEuIAoKYGBge3IgbWVzc2FnZT1GQUxTRX0KIyBMaWJyYXJpZXMKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZmVhdGhlcikKbGlicmFyeShsbWU0KQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkocG5nKQojbGlicmFyeShjb3dwbG90KQoKIyBJbXBvcnQgZGF0YSAoYW5kIGZpeCBvbmUgcGFydGljaXBhbnQgbmFtZSwgYW5kIGZpeCBPd2VuIGFzIEVuZ2xpc2hFeHBvc2VkKQpkYXRhIDwtIHJlYWRfZmVhdGhlcigiLi4vQ2hpbGQgRGF0YS9jaGlsZHh5ZGF0YS5mZWF0aGVyIikgJT4lCiAgbXV0YXRlKHBhcnRpY2lwYW50ID0gY2FzZV93aGVuKAogICAgcGFydGljaXBhbnQgPT0gIkFiMDdvdjA5XzIybSIgfiAiQWIwN292MDlfMzJtIiwKICAgIFRSVUUgfiBwYXJ0aWNpcGFudAogICkpICU+JQogIG11dGF0ZShsYW5ndWFnZSA9IGNhc2Vfd2hlbigKICAgIHBhcnRpY2lwYW50ID09ICJPd2VuVHdpbjAzMDIxMl80eTJtIiB+ICJFbmdsaXNoRXhwb3NlZCIsCiAgICBUUlVFIH4gbGFuZ3VhZ2UKICApKQoKIyBHZXQgYWdlcwphZ2VzIDwtIHJlYWRfY3N2KCJjaGlsZHJlbmFnZXMuY3N2IikKZGF0YSA8LSBkYXRhICU+JSBsZWZ0X2pvaW4oYWdlcywgYnkgPSAicGFydGljaXBhbnQiKQpkYXRhICU+JSBzZWxlY3QocGFydGljaXBhbnQsbGFuZ3VhZ2UsYWdlKSAlPiUgZGlzdGluY3QoKSAjIHByaW50IGRhdGEgdGFibGUKCiMgSGlzdG9ncmFtIG9mIGFnZXMKZGF0YSAlPiUgc2VsZWN0KHBhcnRpY2lwYW50LGxhbmd1YWdlLGFnZSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGdncGxvdChhZXMoeCA9IGFnZSkpICsgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICJyb3lhbGJsdWUiKSArIGdndGl0bGUoIkFnZXMgaW4gRnVsbCBEYXRhc2V0IikKYGBgCgojIFJlbW92aW5nIERpc2NhcmRlZCBLaWRzICh0byBjb21lKQoKVGhpcyBpcyB0aGUgcGFydCB3aGVyZSBJIHdhbnQgdG8gcmVtb3ZlIGFsbCBjaGlsZHJlbiB0aGF0IHdlcmUgbm90IGluY2x1ZGVkIGluIHRoZSBBT0kgYW5hbHlzaXMuIEJ1dCBJIGhhdmVuJ3Qgd3JpdHRlbiB0aGUgY29kZSB5ZXQsIHNvLiAKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmFsbGRhdGEgPC0gZGF0YQpkYXRhIDwtIGRhdGEgJT4lCiAgZmlsdGVyKGFnZSA+IDIuMCkgJT4lCiAgZmlsdGVyKHBhcnRpY2lwYW50ICE9ICJPd2VuVHdpbjAzMDIxMl80eTJtIikgJT4lCiAgZmlsdGVyKHBhcnRpY2lwYW50ICE9ICJLaWVyYV84XzIwXzEzIDN5LDVtIikgJT4lCiAgZmlsdGVyKHBhcnRpY2lwYW50ICE9ICJJc2FiZWxsYSA1IHllYXIgb2xkIERlYWYiKQoKYW50aV9qb2luKGFsbGRhdGEsIGRhdGEsIGJ5ID0gInBhcnRpY2lwYW50IikgJT4lIAogIHNlbGVjdChwYXJ0aWNpcGFudCwgcmVjb3JkaW5nLCBhbmFseXNpcywgbGFuZ3VhZ2UsIGdyb3VwLCBhZ2UpICU+JSAKICBkaXN0aW5jdCgpICU+JQogIGZpbHRlcihhZ2UgPiAyLjApCmBgYAoKIyBTaGlmdGluZyBEYXRhICh0byBjb21lKQpUaGVuIHRoZXJlIGFyZSBzb21lIGtpZHMgd2hvc2UgZGF0YSBuZWVkcyB0byBiZSBjb3JyZWN0ZWQgYmVjYXVzZSBvZiBsYXJnZSBvZmZzZXRzIHdoaWNoIHdlIGRldGVjdGVkIHZpYSBbdHdvcHVwcGllcy5uYi5odG1sXSh0d29wdXBwaWVzLm5iLmh0bWwpLiBJIHNob3VsZCBsaXN0IHRob3NlIGtpZHMgaGVyZSwgdG9vLiAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CgojIE5vdyBsZXQncyBhZGQgY2xpcGxlbmd0aHMgYWdhaW4sIGJ1dCB0aGlzIHRpbWUgdG8gZGF0YSwgYW5kIGNhbGN1bGF0ZSBwZXJjZW50YWdlIGxvb2tpbmcgdGltZXMKZGF0YSA8LSBkYXRhICU+JQogIGxlZnRfam9pbihjbGlwbGVuZ3RoLCBieSA9ICJzdG9yeSIpICU+JQogIHNlbGVjdCgtZnJhbWVzKSAlPiUKICBtdXRhdGUoc2VjcyA9IGhpdHMvMTIwLAogICAgICAgICBwZXJjZW50ID0gc2Vjcy9jbGlwX3NlYykKCiMgSGlzdG9ncmFtIQpkYXRhX2NpIDwtIGRhdGEgJT4lIGZpbHRlcihzdHJfZGV0ZWN0KHN0b3J5LCAiQ2luZGVyZWxsYSIpLCBwZXJjZW50ID4gMC4wNCkKZGF0YV9rbSA8LSBkYXRhICU+JSBmaWx0ZXIoc3RyX2RldGVjdChzdG9yeSwgIktpbmdNaWRhcyIpLCBwZXJjZW50ID4gMC4wNCkKZGF0YV8zYiA8LSBkYXRhICU+JSBmaWx0ZXIoc3RyX2RldGVjdChzdG9yeSwgIlRocmVlQmVhcnMiKSwgcGVyY2VudCA+IDAuMDQpCmRhdGFfcnIgPC0gZGF0YSAlPiUgZmlsdGVyKHN0cl9kZXRlY3Qoc3RvcnksICJSZWRSaWRpbmciKSwgcGVyY2VudCA+IDAuMDQpCgpnZ3Bsb3QoZGF0YV9jaSwgYWVzKHggPSBwZXJjZW50KSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgZmFjZXRfZ3JpZChhb2kgfiBzdG9yeSkgKyB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwKSwgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpICsgeWxhYigiIikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDAsIDEsIC4xKSkKCmdncGxvdChkYXRhX2ttLCBhZXMoeCA9IHBlcmNlbnQpKSArIGdlb21faGlzdG9ncmFtKCkgKyBmYWNldF9ncmlkKGFvaSB+IHN0b3J5KSArIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDApLCBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSkgKyB5bGFiKCIiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgMSwgLjEpKQoKZ2dwbG90KGRhdGFfM2IsIGFlcyh4ID0gcGVyY2VudCkpICsgZ2VvbV9oaXN0b2dyYW0oKSArIGZhY2V0X2dyaWQoYW9pIH4gc3RvcnkpICsgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCksIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpKSArIHlsYWIoIiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLCAxLCAuMSkpCgpnZ3Bsb3QoZGF0YV9yciwgYWVzKHggPSBwZXJjZW50KSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgZmFjZXRfZ3JpZChhb2kgfiBzdG9yeSkgKyB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwKSwgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpICsgeWxhYigiIikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDAsIDEsIC4xKSkKCmBgYAoKIyBTYXZlIQpHcmVhdC4gTGV0J3Mgc2F2ZSB0aGlzIGFzIGBjbGVhbmVkY2hpbGR4eWRhdGEuY3N2Jy4gCgpgYGB7cn0KIyBQdWxsIGFwYXJ0IGNvbmRpdGlvbiBjb2x1bW5zCmRhdGEgPC0gZGF0YSAlPiUKICBzZXBhcmF0ZShjb25kaXRpb24sIGludG8gPSBjKCJzdG9yeSIsICJjbGlwbnVtIiwgImRpcmVjdGlvbiIsICJtZWRpYSIpLCBzZXAgPSAiXyIpICU+JQogIHVuaXRlKHN0b3J5LCBjbGlwbnVtLCBjb2wgPSAic3RvcnkiLCBzZXAgPSAiXyIpICU+JQogIHNlbGVjdCgtbWVkaWEpIAoKIyBBIGJpdCBtb3JlIGNsZWFuaW5nIHVwCmRhdGEgPC0gZGF0YSAlPiUKICBtdXRhdGUoZGlyZWN0aW9uID0gY2FzZV93aGVuKAogICAgZGlyZWN0aW9uID09ICJGVyIgfiAiZm9yd2FyZCIsCiAgICBkaXJlY3Rpb24gPT0gIkVSIiB+ICJyZXZlcnNlZCIKICApKSAlPiUKICBtdXRhdGUobGFuZ3VhZ2UgPSBjYXNlX3doZW4oCiAgICBsYW5ndWFnZSA9PSAiU2lnbkxhbmd1YWdlRXhwb3NlZCIgfiAic2lnbiIsCiAgICBsYW5ndWFnZSA9PSAiRW5nbGlzaEV4cG9zZWQiIH4gImVuZ2xpc2giCiAgKSkgJT4lCiAgbXV0YXRlKGdyb3VwID0gYXMuZmFjdG9yKGdyb3VwKSwKICAgICAgICAgZ2VuZGVyID0gYXMuZmFjdG9yKGdlbmRlciksCiAgICAgICAgIGxhbmd1YWdlID0gYXMuZmFjdG9yKGxhbmd1YWdlKSwKICAgICAgICAgc3RvcnkgPSBhcy5mYWN0b3Ioc3RvcnkpLAogICAgICAgICBkaXJlY3Rpb24gPSBhcy5mYWN0b3IoZGlyZWN0aW9uKSkKCiMgU2F2ZSBhcyBjc3YgYW5kIGZlYXRoZXIgKGZlYXRoZXIgcHJlc2VydmVzIGNvbHVtbiB0eXBlcyBmb3IgUikKd3JpdGVfY3N2KGRhdGEsIi4uL0NoaWxkIERhdGEvY2xlYW5lZGNoaWxkeHlkYXRhLmNzdiIpCndyaXRlX2ZlYXRoZXIoZGF0YSwiLi4vQ2hpbGQgRGF0YS9jbGVhbmVkY2hpbGR4eWRhdGEuZmVhdGhlciIpCmBgYAoKIyBQYXJ0aWNpcGFudCBUYWJsZQoKTm93IHdlIGNhbiBwcmVzZW50IHRoZSBmb2xsb3dpbmcgdGFibGUgYWJvdXQgb3VyIHBhcnRpY2lwYW50cy4gCgpgYGB7cn0KcGFydGljaXBhbnRzIDwtIGRhdGEgJT4lCiAgc2VsZWN0KHBhcnRpY2lwYW50LCBnZW5kZXIsIGxhbmd1YWdlLCBhZ2UpICU+JQogIGRpc3RpbmN0KCkKCnBhcnRpY2lwYW50c19uIDwtIHBhcnRpY2lwYW50cyAlPiUKICBjb3VudChnZW5kZXIsIGxhbmd1YWdlKSAlPiUKICBzcHJlYWQoZ2VuZGVyLCBuKQoKcGFydGljaXBhbnRzX2FnZSA8LSBwYXJ0aWNpcGFudHMgJT4lCiAgZ3JvdXBfYnkobGFuZ3VhZ2UpICU+JQogIHN1bW1hcmlzZShhZ2VfbSA9IHJvdW5kKG1lYW4oYWdlKSwgMSksIAogICAgICAgICAgICBhZ2Vfc2QgPSByb3VuZChzZChhZ2UpLCAxKSwKICAgICAgICAgICAgYWdlX21pbiA9IHJhbmdlKGFnZSlbMV0sCiAgICAgICAgICAgIGFnZV9tYXggPSByYW5nZShhZ2UpWzJdKSAlPiUKICBtdXRhdGUoYWdlX3JhbmdlID0gcGFzdGUoYWdlX21pbiwgYWdlX21heCwgc2VwID0gIiAtICIpKSAlPiUKICBzZWxlY3QoLWFnZV9taW4sIC1hZ2VfbWF4KSAlPiUKICBtdXRhdGUoYWdlX21lYW4gPSBwYXN0ZShhZ2VfbSwgYWdlX3NkLCBzZXAgPSAiwrEiKSkgJT4lCiAgc2VsZWN0KC1hZ2VfbSwgLWFnZV9zZCkgJT4lCiAgc2VsZWN0KGxhbmd1YWdlLCBhZ2VfbWVhbiwgYWdlX3JhbmdlKQoKbGVmdF9qb2luKHBhcnRpY2lwYW50c19uLCBwYXJ0aWNpcGFudHNfYWdlLCBieSA9ICJsYW5ndWFnZSIpCmBgYAoKIyBBbmFseXNpcyBUaW1lIQoKRmlyc3QsIGxldCdzIHRyaW0gZWFjaCBwYXJ0aWNpcGFudCdzIGRhdGEsIGdldHRpbmcgcmlkIG9mIHRoZSBmaXJzdCA2MCBzYW1wbGVzICgwLjUgc2VjcykuIFRoZW4gd2UnbGwgZ2V0IHRoZSB0aGUgbWVhbiB4IGFuZCB5IGNvb3JkaW5hdGUgZm9yIGVhY2ggc3RvcnkgZm9yIGVhY2ggcGFydGljaXBhbnQuCgpgYGB7cn0KIyBKdXN0IHRvIGxvYWQgZGF0YSBhZ2FpbiAKZGF0YSA8LSByZWFkX2ZlYXRoZXIoIi4uL0NoaWxkIERhdGEvY2xlYW5lZGNoaWxkeHlkYXRhLmZlYXRoZXIiKQoKZGF0YSA8LSBkYXRhICU+JQogIGdyb3VwX2J5KHBhcnRpY2lwYW50LHRyaWFsKSAlPiUKICBzbGljZSg2MDpuKCkpCgptZWFucyA8LSBkYXRhICU+JQogIGdyb3VwX2J5KHBhcnRpY2lwYW50LHRyaWFsKSAlPiUKICBzdW1tYXJpc2UoeCA9IG1lYW4oeCxuYS5ybT1UUlVFKSwKICAgICAgICAgICAgeSA9IG1lYW4oeSxuYS5ybT1UUlVFKSkKaGVhZChtZWFucywxMCkKYGBgCgpBbmQgSSBjYW4gZ2V0IHggb3IgeSBwbG90cyBvZiBvbmUgcGFydGljaXBhbnQgYWNyb3NzIDQgc3Rvcmllcy4gTGV0J3MgZG8gRW1tZXQuIFdlJ2xsIHNldCB0aGUgeCBhbmQgeSBsaW1pdHMgdG8gdGhlIHdob2xlIHdpZHRoIG9mIHRoZSBUb2JpaSBtb25pdG9yICgxNjAweDEyMDApLiBCdXQgYmVjYXVzZSBUb2JpaSBjb25zaWRlcnMgKDAsMCkgdG8gYmUgdGhlIHVwcGVyIGxlZnQgY29ybmVyIChhbmQgbm90IHRoZSBib3R0b20gbGVmdCBjb3JuZXIpLCB3ZSBhbHNvIG5lZWQgdG8gZmxpcCB0aGUgeSBheGlzLiAKCmBgYHtyfQplbW1ldCA8LSBmaWx0ZXIoZGF0YSxwYXJ0aWNpcGFudD09ImVtbWV0XzEyXzEwXzEyX0NPREEiKSAlPiUgbXV0YXRlKHkgPSB5Ki0xKQpnZ3Bsb3QoZW1tZXQsYWVzKHg9eCx5PXksY29sb3I9c3RvcnkpKSArIGdlb21fcG9pbnQoc2l6ZT0wLjEpICsgZ2VvbV9wYXRoKCkgKyBmYWNldF93cmFwKCJzdG9yeSIsbmNvbD00LG5yb3c9MikgKyBndWlkZXMoY29sb3I9Im5vbmUiKSArIHNjYWxlX3hfY29udGludW91cyhsaW1pdD1jKDAsMTYwMCkpICsgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0PWMoLTEyMDAsMCkpCmBgYAoKQ29vbCwgeWVhaD8gCgojIElRUiAKTm93IGxldCdzIGdldCB0aGUgbWlkZGxlIDUwJSAoYWthIHRoZSBJUVIpIG9mIHggYW5kIHkgZm9yIGVhY2ggcGFydGljaXBhbnQncyBzdG9yeSAod2UndmUgYWxyZWFkeSB0cmltbWVkIHRoZSBmaXJzdCA2MCBzYW1wbGVzKS4gVGhhdCBzaG91bGQgYWxzbyB0YWtlIGNhcmUgb2YgZnVydGhlciB3ZWlyZCBvdXRsaWVycy4gQW5kIHdlIGFyZSBkZWZpbmluZyAidmlld2luZyBzcGFjZSIgYXMgdGhlIElRUiBvZiB0aGUgeCBhbmQgeSBheGlzLiAKCmBgYHtyfQppcXIgPC0gZGF0YSAlPiUKICBncm91cF9ieShwYXJ0aWNpcGFudCx0cmlhbCkgJT4lCiAgc3VtbWFyaXNlKHhJUVIgPSBJUVIoeCxuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgIHlJUVIgPSBJUVIoeSxuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgIHhtZWQgPSBtZWRpYW4oeCwgbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5bWVkID0gbWVkaWFuKHksIG5hLnJtPVRSVUUpKSAlPiUKICB1bmdyb3VwKCkKaGVhZChpcXIsMTApCgojIEpvaW4gcGFydGljaXBhbnQgaW5mbyBiYWNrIGludG8gSVFSIHRhYmxlCnBhcnRpY2lwYW50aW5mbyA8LSBkYXRhICU+JQogIHNlbGVjdChwYXJ0aWNpcGFudCwgdHJpYWwsIGFnZSwgZ3JvdXAsIGdlbmRlciwgbGFuZ3VhZ2UsIHN0b3J5LCBkaXJlY3Rpb24sIG1hcmssIHJlcGV0aXRpb24pICU+JQogIGRpc3RpbmN0KCkKCmlxciA8LSBsZWZ0X2pvaW4oaXFyLCBwYXJ0aWNpcGFudGluZm8sIGJ5ID0gYygicGFydGljaXBhbnQiLCJ0cmlhbCIpKQpgYGAKCkFuZCBjaGVjayBvdXQgdGhlIGhpc3RvZ3JhbXMuIEkgdHJ1bmNhdGVkIHRoZSB5LWF4aXMgYXQgMTAwIHRvIGJldHRlciBzZWUgb3V0bGllcnMuIAoKYGBge3J9CmlxciAlPiUgCiAgZ2F0aGVyKGF4aXMsaXFyLHhJUVI6eUlRUikgJT4lCiAgZ2dwbG90KGFlcyh4PWlxcixmaWxsPWF4aXMpKSArIGdlb21faGlzdG9ncmFtKCkgKyBmYWNldF9ncmlkKGF4aXN+LikgKyAKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCw1MCkpCmBgYAoKU28gd2Ugc2VlIHNvbWUgb3V0bGllcnMuIFdobyBhcmUgdGhvc2U/IExldCdzIGdldCBhIHRhYmxlIG9mIHRoZW0uIFJldmlldyB0aG9zZSBBRlRFUiBJJ3ZlIGRvbmUgdGhlIGNsZWFudXBzIG9mIGNvdXJzZS4gCgpgYGB7cn0KeG91dGxpZXJzIDwtIGlxciAlPiUKICBhcnJhbmdlKGRlc2MoeElRUikpICU+JQogIHNsaWNlKDE6MTApCnlvdXRsaWVycyA8LSBpcXIgJT4lCiAgYXJyYW5nZShkZXNjKHlJUVIpKSAlPiUKICBzbGljZSgxOjEwKQpgYGAKCk5leHQsIGNoZWNrIHRoZSBtZWRpYW5zLgoKYGBge3J9CmlxciAlPiUgCiAgZ2F0aGVyKGF4aXMsbWVkLHhtZWQ6eW1lZCkgJT4lCiAgZ2dwbG90KGFlcyh4PW1lZCxmaWxsPWF4aXMpKSArIGdlb21faGlzdG9ncmFtKCkgKyBmYWNldF9ncmlkKGF4aXN+LikgKyAKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCw1MCkpCmBgYAoKU08gSSBuZWVkIHRvIHJldmlldyB0aG9zZSB0b28uIEFmdGVyIGNsZWFuaW5nIHVwL3JlbW92aW5nIGtpZHMuCgpgYGB7cn0KaXFyLmdhdGhlciA8LSBpcXIgJT4lIGdhdGhlcihheGlzLHZhbHVlLHhJUVI6eW1lZCkKaXFyLmlxciA8LSBmaWx0ZXIoaXFyLmdhdGhlcixheGlzPT0ieElRUiIgfCBheGlzPT0ieUlRUiIpCmlxci5tZWQgPC0gZmlsdGVyKGlxci5nYXRoZXIsYXhpcz09InhtZWQiIHwgYXhpcz09InltZWQiKQoKCmdncGxvdChpcXIuaXFyLGFlcyh4PWxhbmd1YWdlLHk9dmFsdWUsZmlsbD1kaXJlY3Rpb24pKSArIAogIGdlb21fYm94cGxvdCgpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEpKSArCiAgZmFjZXRfZ3JpZCgufmF4aXMpCmBgYAoKQW5kIHRoZSBtZWRpYW4geCBhbmQgeSBwb3NpdGlvbiAodGhpcyBhc3N1bWVzIGFsbCBjYWxpYnJhdGlvbnMgYXJlIGNvcnJlY3QpOgoKYGBge3J9CmdncGxvdChpcXIubWVkLGFlcyh4PWxhbmd1YWdlLHk9dmFsdWUsZmlsbD1kaXJlY3Rpb24pKSArIAogIGdlb21fYm94cGxvdCgpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEpKSArCiAgZmFjZXRfZ3JpZCgufmF4aXMpCmBgYAoKRmlyc3QsIGRvZXMgcmV2ZXJzYWwgYW5kIGxhbmd1YWdlIGV4cGVyaWVuY2UgaGF2ZSBhbiBlZmZlY3Qgb24gWCBJUVI/IFdlIGhhdmUgcmFuZG9tIGludGVyY2VwdHMgZm9yIGVhY2ggcGFydGljaXBhbnQgYW5kIG1lZGlhLCBhbmQgYSByYW5kb20gc2xvcGUgYWRqdXN0bWVudCBmb3IgcmV2ZXJzZWQgZm9yIGVhY2ggcGFydGljaXBhbnQuIAoKYGBge3J9CnhpcXIucmV2ZXJzYWwgPC0gbG1lcih4SVFSIH4gZGlyZWN0aW9uICogbGFuZ3VhZ2UgKyAoZGlyZWN0aW9ufHBhcnRpY2lwYW50KSArICgxfHN0b3J5KSwgZGF0YSA9IGlxcikKc3VtbWFyeSh4aXFyLnJldmVyc2FsKSRjb2VmZmljaWVudHMKYGBgCgpUaGF0J3MgZmluZSwgd2UncmUgbm90IGV4YWN0bHkgcHJlZGljdGluZyBjaGFuZ2VzIGFsb25nIHRoZSB4LWF4aXMuIFRoZSB5LWF4aXMgaXMgd2hhdCB3ZSBhcmUgcmVhbGx5IGludGVyZXN0ZWQgaW4hIDopIApgYGB7cn0KeWlxci5yZXZlcnNhbCA8LSBsbWVyKHlJUVIgfiBkaXJlY3Rpb24gKiBsYW5ndWFnZSArIChkaXJlY3Rpb258cGFydGljaXBhbnQpICsgKDF8c3RvcnkpLCBkYXRhID0gaXFyKQpzdW1tYXJ5KHlpcXIucmV2ZXJzYWwpJGNvZWZmaWNpZW50cwpgYGAKCgojIFZpZXdpbmcgU3BhY2UgQ2hhcnRzCkkgd2FudCB0byBsZWFybiBob3cgdG8gbWFrZSByZWN0YW5nbGUgcGxvdHMgc28gaGVyZSB3ZSBnby4gVXNpbmcgZWFjaCBwYXJ0aWNpcGFudCdzIGZvdXIgeCBhbmQgeSBtZWRpYW5zIGFuZCA0IHggYW5kIHkgSVFScyAob25lIHNldCBmb3IgZWFjaCBzdG9yeSwgZm9yIDQgc3RvcmllcykuIFNvIEkgY2FuIGdldCB0aGUgbG9naWMgYW5kIGNvZGUgZG93bi4gTGV0J3MgYXNzdW1lIGFsbCBjYWxpYnJhdGlvbnMgd2VyZSBjb3JyZWN0LiBIZXJlJ3MgdGhlIGNoYXJ0IGZvciB0aGUgd2hvbGUgbWVkaWEgc2l6ZSBvZiAxNDQweDEwODAgKGFzIHJlcG9ydGVkIGluIFRvYmlpKS4gCmBgYHtyfQojIEluIHRoaXMgb3JkZXIsIHdlJ2xsIGdldCBhIGdyYW5kIG1lZGlhbiBieSB0YWtpbmcgYSBwYXJ0aWNpcGFudCdzIG1lZGlhbiBhY3Jvc3MgdGhlaXIgNCBzdG9yaWVzLCB0aGFuIHRoZSBtZWRpYW4gZm9yIGZvcndhcmQgYW5kIHJldmVyc2UgYWNyb3NzIGFsbCBwYXJ0aWNpcGFudHMuIAptZWRpYW5zIDwtIGlxciAlPiUKICBncm91cF9ieShwYXJ0aWNpcGFudCxkaXJlY3Rpb24pICU+JQogIHN1bW1hcmlzZSh4SVFSID0gbWVkaWFuKHhJUVIsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5SVFSID0gbWVkaWFuKHlJUVIsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB4bWVkID0gbWVkaWFuKHhtZWQsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5bWVkID0gbWVkaWFuKHltZWQsbmEucm09VFJVRSkpICU+JQogIGdyb3VwX2J5KGRpcmVjdGlvbikgJT4lIAogIHN1bW1hcmlzZSh4SVFSID0gbWVkaWFuKHhJUVIsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5SVFSID0gbWVkaWFuKHlJUVIsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB4ID0gbWVkaWFuKHhtZWQsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5ID0gbWVkaWFuKHltZWQsbmEucm09VFJVRSkpCgptZWRpYW5zIDwtIG1lZGlhbnMgJT4lCiAgbXV0YXRlKHkgPSB5Ki0xLAogICAgICAgICB4bWluID0geC0oeElRUi8yKSwKICAgICAgICAgeG1heCA9IHgrKHhJUVIvMiksCiAgICAgICAgIHltaW4gPSB5LSh5SVFSLzIpLAogICAgICAgICB5bWF4ID0geSsoeUlRUi8yKSkKCmltZyA8LSByZWFkUE5HKCJjaW5keS5wbmciKQpnIDwtIHJhc3Rlckdyb2IoaW1nLCBpbnRlcnBvbGF0ZT1UUlVFLCB3aWR0aD11bml0KDEsIm5wYyIpLCBoZWlnaHQ9dW5pdCgxLCJucGMiKSkgCgpnZ3Bsb3QobWVkaWFucywgYWVzKGZpbGw9ZGlyZWN0aW9uLGNvbG9yPWRpcmVjdGlvbikpICsKICBhbm5vdGF0aW9uX2N1c3RvbShnLCB4bWluPS1JbmYsIHhtYXg9SW5mLCB5bWluPS1JbmYsIHltYXg9SW5mKSArCiAgZ2VvbV9yZWN0KGFlcyh4bWluPXhtaW4seW1pbj15bWluLHhtYXg9eG1heCx5bWF4PXltYXgpLGFscGhhPS4xKSArIAogIHRoZW1lX21pbmltYWwoKSArIHhsaW0oMCwxNDQwKSArIHlsaW0oLTEwODAsMCkKCgojIGdncGxvdChpcXIuZ2xvYmFsLCBhZXMoZmlsbD1kaXJlY3Rpb24sY29sb3I9ZGlyZWN0aW9uKSkgKwojICAgYW5ub3RhdGlvbl9jdXN0b20oZywgeG1pbj0tSW5mLCB4bWF4PUluZiwgeW1pbj0tSW5mLCB5bWF4PUluZikgKwojICAgZ2VvbV9yZWN0KGFlcyh4bWluPXhtaW4seW1pbj15bWluLHhtYXg9eG1heCx5bWF4PXltYXgpLGFscGhhPS4xKSArIAojICAgdGhlbWVfbWluaW1hbCgpICsgeGxpbSgwLDE0NDApICsgeWxpbSgtMTA4MCwwKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9LTEwODArODg1KSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9LTEwODArNTI1KSArIAojICAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHggPSAzMDAsIHkgPSAtMTA4MCs1NTUsIGxhYmVsID0gInVwcGVyIHNob3VsZGVyIHBvaW50IikgKwojICAgYW5ub3RhdGUoZ2VvbT0icG9pbnQiLCB4ID0gNTM1LCB5ID0gLTEwODArNTI1KSArIAojICAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHggPSA1MzUsIHkgPSAtMTA4MCs5MTAsIGxhYmVsID0gImhlaWdodCBsaW5lIikgKyAKIyAgIGFubm90YXRlKGdlb209InJlY3QiLCB4bWluID0gNTM1LCB4bWF4ID0gNTM1KzM2NSwgeW1pbiA9IC01MjUtNTUxLCB5bWF4ID0gLTEwODArNTI1LCBmaWxsPSJtYXJvb24iLCBjb2xvcj0iYmxhY2siLCBhbHBoYT0wLjUpICsgCiMgICBhbm5vdGF0ZShnZW9tPSJ0ZXh0IiwgeCA9IDcwMCwgeSA9IC05MDAsIGxhYmVsID0gInRvcnNvIikKCmBgYAoKIyBWaWV3aW5nIFNwYWNlIENoYXJ0cyBmb3IgSW5kaXZpZHVhbHMKTm93IGxldCdzIHNlZSB0aGUgdmFyaWF0aW9uIGluIHZpZXdpbmcgc3BhY2VzIGZvciBhbGwgb3VyIGluZGl2aWR1YWxzLiBTaG91bGQgYmUgZnVuLgoKYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTI2fQppcXIuaW5kaXZpZHVhbHMgPC0gaXFyICU+JQogIHJlbmFtZSh4ID0geG1lZCwKICAgICAgICAgeSA9IHltZWQpICU+JQogIG11dGF0ZSh5ID0geSotMSwKICAgICAgICAgeG1pbiA9IHgtKHhJUVIvMiksCiAgICAgICAgIHhtYXggPSB4Kyh4SVFSLzIpLAogICAgICAgICB5bWluID0geS0oeUlRUi8yKSwKICAgICAgICAgeW1heCA9IHkrKHlJUVIvMikpCgpnZ3Bsb3QoaXFyLmluZGl2aWR1YWxzLCBhZXMoZmlsbD1kaXJlY3Rpb24sY29sb3I9ZGlyZWN0aW9uKSkgKwogIGFubm90YXRpb25fY3VzdG9tKGcsIHhtaW49LUluZiwgeG1heD1JbmYsIHltaW49LUluZiwgeW1heD1JbmYpICsKICBnZW9tX3JlY3QoYWVzKHhtaW49eG1pbix5bWluPXltaW4seG1heD14bWF4LHltYXg9eW1heCksYWxwaGE9LjEpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgeGxpbSgwLDE0NDApICsgeWxpbSgtMTA4MCwwKSArIGZhY2V0X3dyYXAoImRpcmVjdGlvbiIpICsKICBnZ3RpdGxlKCJ3aXRoIElRUnMiKQpgYGAKCk5vdyBsZXQncyBtYWtlIE91dGVyIExpbWl0cyBjaGFydHMgd2hpY2ggaXMgSVFSICsvLSAyIFNEcy4gIEJ1dCBJIHdhbnQgdG8gY2hhbmdlIHRoYXQgYmVjYXVzZSBJIGRvbid0IGxpa2UgdGhlIGlkZWEgb2YgbWl4aW5nIElRUnMgYW5kIFNEcy4gCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0yNn0KIyBzZC5pbmRpdmlkdWFscyA8LSBzZWxlY3Qoc2QuaW5kaXZpZHVhbHMscGFydGljaXBhbnQsbWVkaWEseHNkLHlzZCkKIyBpcXJzZC5pbmRpdmlkdWFscyA8LSBsZWZ0X2pvaW4oaXFyLmluZGl2aWR1YWxzLHNkLmluZGl2aWR1YWxzLGJ5PWMoInBhcnRpY2lwYW50IiwibWVkaWEiKSkgJT4lCiMgICBtdXRhdGUoeG1pbiA9IHhtaW4tKDIqeHNkKSwKIyAgICAgICAgICB4bWF4ID0geG1heCsoMip4c2QpLAojICAgICAgICAgIHltaW4gPSB5bWluLSgyKnlzZCksCiMgICAgICAgICAgeW1heCA9IHltYXgrKDIqeXNkKSkKIyAKIyBnZ3Bsb3QoaXFyc2QuaW5kaXZpZHVhbHMsIGFlcyhmaWxsPWRpcmVjdGlvbixjb2xvcj1kaXJlY3Rpb24pKSArCiMgICBhbm5vdGF0aW9uX2N1c3RvbShnLCB4bWluPS1JbmYsIHhtYXg9SW5mLCB5bWluPS1JbmYsIHltYXg9SW5mKSArCiMgICBnZW9tX3JlY3QoYWVzKHhtaW49eG1pbix5bWluPXltaW4seG1heD14bWF4LHltYXg9eW1heCksYWxwaGE9LjEpICsgCiMgICB0aGVtZV9taW5pbWFsKCkgKyB4bGltKDAsMTQ0MCkgKyB5bGltKC0xMDgwLDApICsgZmFjZXRfd3JhcCgiZGlyZWN0aW9uIikgKwojICAgZ2d0aXRsZSgid2l0aCBTRHMiKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0yNn0KIyBpcXJzZC5pbmRpdmlkdWFscyA8LSBpcXJzZC5pbmRpdmlkdWFscyAlPiUKIyAgIGdyb3VwX2J5KGRpcmVjdGlvbikgJT4lCiMgICBkcGx5cjo6c3VtbWFyaXplKHggPSBtZWFuKHgsbmEucm09VFJVRSksCiMgICAgICAgICAgICAgeSA9IG1lYW4oeSxuYS5ybT1UUlVFKSwKIyAgICAgICAgICAgICB4bWluID0gbWVhbih4bWluLG5hLnJtPVRSVUUpLAojICAgICAgICAgICAgIHltaW4gPSBtZWFuKHltaW4sbmEucm09VFJVRSksCiMgICAgICAgICAgICAgeG1heCA9IG1lYW4oeG1heCxuYS5ybT1UUlVFKSwKIyAgICAgICAgICAgICB5bWF4ID0gbWVhbih5bWF4LG5hLnJtPVRSVUUpKQojIGdncGxvdChpcXJzZC5pbmRpdmlkdWFscywgYWVzKGZpbGw9ZGlyZWN0aW9uLGNvbG9yPWRpcmVjdGlvbikpICsKIyAgIGFubm90YXRpb25fY3VzdG9tKGcsIHhtaW49LUluZiwgeG1heD1JbmYsIHltaW49LUluZiwgeW1heD1JbmYpICsKIyAgIGdlb21fcmVjdChhZXMoeG1pbj14bWluLHltaW49eW1pbix4bWF4PXhtYXgseW1heD15bWF4KSxhbHBoYT0uMSkgKyAKIyAgIHRoZW1lX21pbmltYWwoKSArIHhsaW0oMCwxNDQwKSArIHlsaW0oLTEwODAsMCkgKyBmYWNldF93cmFwKCJkaXJlY3Rpb24iKSArCiMgICBnZ3RpdGxlKCJBdmVyYWdlIG9mIGFib3ZlIGNoYXJ0IChyYWluJ3Mgb3V0ZXIgbGltaXRzKSIpCgpgYGA=